/*
============================================================================
 Name			: BlueToothConnector.cpp
 Author	  		: 
 Copyright   	:
 Description 	: Implementation
============================================================================
*/

// INCLUDE FILES

#include "BluetoothServiceSearcher.h"
#include "common.hrh"
/*
============================================================================
CBluetoothServiceSearcher's constructor 
============================================================================
*/
CBluetoothServiceSearcher::CBluetoothServiceSearcher(MBluetoothServiceSearcherObserver& aObs)
  : iObserver(aObs), iPort(KPort), iFoundRfcommProtocol(EFalse)
	{
	}

/*
============================================================================
CBluetoothServiceSearcher's destructor
============================================================================
*/
CBluetoothServiceSearcher::~CBluetoothServiceSearcher()
	{
    delete iSdpSearchPattern;
  
	if (iAgent)
		{
		iAgent->Cancel();		
	    delete iAgent;
		}
	}

/*
============================================================================
Retrives from a remote device a SDP's service record.
On completion calls NextRecordRequestComplete. 
============================================================================
*/
void CBluetoothServiceSearcher::FindServiceByUUIDL(const TBTDevAddr& aTarget, const TUUID& aUUID)
	{
	/*
	============================================================================
	Deletes any previous existing SDP agent and search pattern
	============================================================================
	*/
	delete iSdpSearchPattern;
	iSdpSearchPattern = NULL;
	delete iAgent;
	iAgent = NULL;
	/*
	============================================================================
	Bluetooth's service class records are stored into the SDP database.
	In order to access/get SDP's records you need to use CSdpAgent.
	CSdpAgent can only been used if the address of a remote Bluetooth device has been identified.
	Also the class using CSdpAgent must implement the MSdpAgentNotifier interface in order
	to handle SDP's responses. See SDK for more details about CSdpAgent and MSdpAgentNotifier
	============================================================================
	*/
	iAgent=CSdpAgent::NewL(*this,aTarget);
	/*
	============================================================================
	In order to retrive only the SDP record you are interested in, SDP provides the filter
	CSdpSearchPattern. CSdpSearchPattern is an array of TUUID (Bluetooth Universally Unique Identifier) 
	that uniquelly identifies a service class.
	Adding a service class to the filter is done by calling subsequentially CSdpSearchPattern::AddL().
	In our example we are interested only in seeing if the remote device provides the RPS service, but you could
	for example ask the SDP server to return all Bluetooth services that support the RFCOMM protocol.
	After adding all the TUUID you are interested in into CSdpSearchPattern you need to move it into
	CSdpAgent by calling CSdpAgent::SetRecordFilterL().
	============================================================================
	*/
	iSdpSearchPattern=CSdpSearchPattern::NewL();
	iSdpSearchPattern->AddL(aUUID);
	iAgent->SetRecordFilterL(*iSdpSearchPattern);
	/*
	============================================================================
	We now need to get the handle of the record on the remote device that matches the service class we set previously in
	CSdpSearchPattern. You need to use CSdpAgent::NextRecordRequestL(). NextRecordRequestL() is  an asynchronous function
	and when completed it will call the callback NextRecordRequestComplete() from the MSdpAgentNotifier interface
	passed in the NewL. Note that as mention above CSdpSearchPattern could contain more then one service class TUUID and you can get 
	the next (if available) service record by calling subsequently NextRecordRequestL().
	============================================================================
	*/
	iAgent->NextRecordRequestL();
	}

/*
============================================================================
Called when a service record request (CSdpAgent::NextRecordRequestComplete()) operation is completed
============================================================================
*/
void CBluetoothServiceSearcher::NextRecordRequestComplete(TInt aError,TSdpServRecordHandle aHandle,TInt aTotalRecordsCount)
	/*
	=================================================================================
	NextRecordRequestComplete is invoked each time a complete full SDP service record is retrieved from the remote Bluetooth target.
	NextRecordRequestComplete is the CSdpAgent::NextRecordRequestL's callback 
	If there is no error, we then invoke CSdpAgent::AttributeRequestL to browse the attributes of the SDP record.
	If there are no more records to browse then the error will be KErrEof.
	=================================================================================
	*/
	{
	TBool terminated=EFalse;
		
	if(aError == KErrNone)
		{
		if(aTotalRecordsCount==0)
			{
			/*
			=================================================================================
			This covers the case where CSdpAgent::NextRecordRequestL didn't find any SDP's records matching our RPS's service class
			=================================================================================
			*/
			iObserver.OnServiceSearchComplete(iPort, KErrNotFound);
			}
		else
			{				
			iPort=KPort;
			/*
			=================================================================================
			If there are SDP's records containing our class service, we need to browse the SDP record to retrive
			the port of the service. The port is then used with the remote BT's address by the Master in order to connect to the slave.
			CSdpAgent::AttributeRequestL is an asynchronous call. When the attributes have been retrived from the remote device then it
			calls AttributeRequestResult from the MSdpAgentNotifier interface. AttributeRequestL takes two parameters: the first one
			is the handle of the SDP's record that is a TUint32 (TSdpServRecordHandle) and the second parameter is one of the "Universal Attributes"
			defined in btsdp.h; in our example we use KSdpAttrIdProtocolDescriptorList because we are only interested in SDP's record that
			contains the RFCOMM protocol. Note that there is another overload AttributeRequestL where the search is done
			with a range of attibutes instead of only one. You need to use AttributeRequestL(TSdpServRecordHandle aHandle, const CSdpAttrIdMatchList& aMatchList), 
			where CSdpAttrIdMatchList is the list of attributes you want to filter. Also you can use your own builder class in order 
			to browse the SDP's record attributes. In this case you need to use
			AttributeRequestL(MSdpElementBuilder* aBuilder, TSdpServRecordHandle aHandle, TSdpAttributeID aAttrID) for a single attribute or
			AttributeRequestL(MSdpElementBuilder* aBuilder,TSdpServRecordHandle aHandle,const CSdpAttrIdMatchList& aMatchList)
			for a range of attributes. If you don't want to provide your own MSdpElementBuilder then you can use directly
			CSdpAttrValue returned from AttributeRequestResult. See below.
			=================================================================================
			*/
			TRAPD(err, iAgent->AttributeRequestL(aHandle,KSdpAttrIdProtocolDescriptorList));
			if(err != KErrNone)
				{
				iObserver.OnServiceSearchComplete(iPort, err);
				}
			}
		}
	else
		{			
		/*
		=================================================================================
		This covers the case where there are no more SDP's records left to be read (KErrEof) or an SDP's error occurs.
		=================================================================================
		*/
		iObserver.OnServiceSearchComplete(iPort, aError);
		terminated=ETrue;
		}
	}

/*
============================================================================
Called when an attribute request (CSdpAgent::AttributeRequestL()) wants to pass up a result
============================================================================
*/
void CBluetoothServiceSearcher::AttributeRequestResult(TSdpServRecordHandle /*aHandle*/, TSdpAttributeID /*aAttrID*/, CSdpAttrValue* aAttrValue)
	{
	/*
	=================================================================================
	AttributeRequestResult is invoked each time an attribute-value is retrieved from the SDP record. AttributeRequestResult is the CSdpAgent::AttributeRequestL's callback.
	We need to browse the attribute-value to decide whether we have a match with our initial requirements
	CSdpAttrValue::AcceptVisitorL passes the attribute value to the VisitAttributeValueL callback
	from MSdpAttributeValueVisitor
	=================================================================================
	*/
	TRAPD(err,aAttrValue->AcceptVisitorL(*this));
	if(err != KErrNone)
		{
	    iObserver.OnServiceSearchComplete(iPort, err);			
		}
	}

/*
============================================================================
Called to pass an attribute value
============================================================================
*/
void CBluetoothServiceSearcher::VisitAttributeValueL(CSdpAttrValue &aValue, TSdpElementType aType)
	{
	/*
	=================================================================================
	Here we browse the attributes to see if we have a match with our initial requirements.
	In our case we are interested only in RPS's services that used only the KRFCOMM protocol. If there is a match
	then we need to get the port of the RPS's service. VisitAttributeValueL is called for each
	attribute. When all the attributes have been browsed then AttributeRequestComplete callback below is called.
	=================================================================================
	*/
	switch(aType)
		{
	case ETypeUUID:
		if(aValue.UUID() == TUUID(KRFCOMM))
			{
			iFoundRfcommProtocol = ETrue;	
			}
    	break;
	case ETypeUint:
        if(iFoundRfcommProtocol)
	        {
	        //get the RFCOMM's service port number
	        iPort=aValue.Uint();
	        iFoundRfcommProtocol = EFalse;
	        }
        break;
	default:
		break;
		}
	}

/*
=================================================================================
Called when an attribute request (CSdpAgent::AttributeRequestL()) wants to  signal the completion of
an attribute request.
=================================================================================
*/
void CBluetoothServiceSearcher::AttributeRequestComplete(TSdpServRecordHandle /*aHandle*/, TInt aError)
	{
	/*
	=================================================================================
	In our example we finish on the first match but you can use iAgent->NextRecordRequestL() to search for
	another record (if any).
	=================================================================================
	*/
	iObserver.OnServiceSearchComplete(iPort, aError);
	}

/*
=================================================================================
Indicates that subsequent elements added belong to a DES or DEA
=================================================================================
*/
void CBluetoothServiceSearcher::StartListL(CSdpAttrValueList& /*aList*/)
	{
	//From MSdpAttributeValueVisitor.
	//Not used
	}

/*
=================================================================================
Indicates the end of a list started by StartListL().
=================================================================================
*/
void CBluetoothServiceSearcher::EndListL()
	{
	//From MSdpAttributeValueVisitor.
	//Not used
	}
